<template>
  <basic-drawer
    :visible="visible"
    :title="title"
    ok-text="保存配置"
    :loading="saveLoading"
    @ok="handleSubmit"
    @open="handleBeforeOpen"
    @close="handleBeforeClose"
    @cancel="emits('update:visible', false)">
    <a-form
      ref="formRef"
      :model="formData"
      :rules="formRules"
      layout="vertical">
      <a-form-item
        field="name"
        label="规则名称"
        hide-asterisk
        asterisk-position="end"
        required>
        <a-input
          v-model="formData.name"
          :max-length="20"
          class="!w-100"
          placeholder="请输入规则名称">
        </a-input>
      </a-form-item>
      <a-form-item
        label="匹配规则"
        asterisk-position="end"
        hide-asterisk
        required
        class="rule-help-item">
        <matching-rule-view
          ref="matchingView"
          v-model="ruleGroups"
          class="w-full"></matching-rule-view>
      </a-form-item>
      <a-form-item
        label="触发条件"
        asterisk-position="end"
        hide-asterisk
        required>
        <section class="flex gap-x-2">
          <div class="h-8 leading-8">当</div>
          <a-form-item field="module_config.cycle" hide-label required>
            <section class="flex-center gap-x-2">
              <section class="cloud-diverse-select">
                <a-input-number
                  v-model="formData.module_config.cycle!"
                  :min="1"
                  :max="formData.cycle_unit === 1 ? 365 : 99999"
                  :controls="false"
                  :precision="0"
                  placeholder="请输入"
                  :allow-clear="false"
                  class="!w-110px"
                  @blur="
                    () =>
                      formData.module_config.cycle
                        ? formData.module_config.cycle
                        : 1
                  " />
                <a-select
                  v-model="formData.cycle_unit"
                  class="!w-fit"
                  :options="cacheTimeOptions.slice(1, 4)">
                </a-select>
              </section>
              内超过
            </section>
          </a-form-item>
          <a-form-item
            field="module_config.count"
            hide-label
            asterisk-position="end"
            required>
            <section class="flex-center gap-x-2 whitespace-nowrap">
              <section class="cloud-diverse-select">
                <a-input-number
                  v-model="formData.module_config.count!"
                  :min="1"
                  :max="99999"
                  :precision="0"
                  :controls="false"
                  placeholder="请输入"
                  class="!w-110px">
                </a-input-number>
                <div class="suffix">次</div>
              </section>
              触发执行策略
            </section>
          </a-form-item>
        </section>
      </a-form-item>
      <a-form-item
        field="action"
        label="执行策略"
        hide-asterisk
        asterisk-position="end"
        required>
        <template #label>
          <div class="flex flex-col">
            <span>执行策略</span>
            <span class="text-xs/5 text-5">规则生效时，执行指定动作：</span>
          </div>
        </template>
        <a-select
          v-model="formData.action"
          placeholder="请选择执行动作"
          class="!w-100"
          :options="executionOptions"
          @change="setDefaultType" />
      </a-form-item>
      <section v-if="formData.action === 1" class="mb-6">
        <a-form-item
          label="响应类型"
          required
          field="response_page.type"
          hide-asterisk>
          <a-select
            v-model="formData.response_page.type"
            class="!w-100"
            placeholder="请选择响应类型"
            @change="setDefaultCode">
            <a-option
              v-for="item in RESPONSE_TYPE_LIST"
              :key="item.value"
              :label="item.label"
              :value="item.value" />
          </a-select>
        </a-form-item>
        <a-form-item
          label="响应代码"
          required
          field="response_page.code"
          hide-asterisk>
          <a-input-number
            v-model.number="formData.response_page.code"
            hide-button
            :max-length="30"
            :precision="0"
            class="!w-100"
            :disabled="formData.response_page.type === 1"
            placeholder="请输入响应代码"></a-input-number>
        </a-form-item>
        <a-form-item
          v-if="formData.response_page.type !== 1"
          label="响应内容"
          hide-asterisk
          class="!mb-2"
          required
          field="response_page.body">
          <a-textarea
            v-model="formData.response_page.body"
            :max-length="10000"
            show-word-limit
            :auto-size="{ minRows: 5, maxRows: 5 }"
            class="w-full h-fit"
            :placeholder="`请输入显示页面的${getOptionsLabel(
              RESPONSE_TYPE_LIST,
              formData.response_page.type
            )}`"></a-textarea>
        </a-form-item>
        <section
          v-if="formData.response_page.type !== 1"
          class="flex items-center gap-x-6px w-fit cursor-pointer"
          @click="previewWithNewPage(formData.response_page.body)">
          <a-link :hoverable="false">预览效果 </a-link><i-icons-new-page />
        </section>
      </section>
      <a-form-item
        field="module_config.duration"
        label="执行持续时间"
        hide-asterisk
        asterisk-position="end"
        required>
        <section class="w-100 flex items-center cloud-diverse-select">
          <a-input-number
            v-model="formData.module_config.duration!"
            :min="1"
            :max="formData.duration_unit === 1 ? 365 : 99999"
            :controls="false"
            :precision="0"
            placeholder="请输入"
            class="flex-1">
          </a-input-number>
          <a-select
            v-model="formData.duration_unit"
            class="!w-78px"
            :options="cacheTimeOptions.slice(1, 4)">
          </a-select>
        </section>
      </a-form-item>
      <a-form-item
        v-if="list.length > 0"
        field="order"
        label="执行优先级"
        hide-asterisk
        asterisk-position="end"
        class="!mb-0"
        required>
        <section class="flex flex-col">
          <a-select
            v-model="formData.order"
            placeholder="请选择执行优先级"
            class="!w-100"
            :options="getOption"
            @change="handleChange" />
          <a-form-item
            v-if="formData.order === A_EXECUTION_PRIORITY.CUSTOM"
            field="priority"
            hide-label
            asterisk-position="end"
            class="!mb-0 mt-2"
            required>
            <a-select
              v-model="formData.priority"
              class="w-[336px]"
              placeholder="优先触发创建的规则，再触发选择的规则">
              <a-option
                v-for="item in props?.record?.id ? filterList : list"
                :key="item.id"
                :label="item.name"
                :value="item.priority" />
            </a-select>
          </a-form-item>
          <span
            v-if="formData.order === A_EXECUTION_PRIORITY.CUSTOM"
            class="text-5 text-xs/5"
            >在此规则前执行。</span
          >
        </section>
      </a-form-item>
    </a-form>
  </basic-drawer>
</template>
<script lang="ts" setup>
import type { WafListItem } from '@/apis/model/waf'
import {
  addApiWafApi,
  getApiWafApi,
  getApiWafQueryApi,
  updateApiWafApi
} from '@/apis/modules/waf'
import type { CloudFilterBarState } from '@/components/filter-bar/types'
import type { IMatchingGroup } from '@/components/MatchingRule/types'
import { getFieldValue } from '@/components/MatchingRule/utils'
import { A_CACHE_TIME } from '@/constants'
import { type FieldRule, type FormInstance } from '@arco-design/web-vue'
import { omit } from 'lodash-es'
import { v4 as uuidV4 } from 'uuid'
interface IProps {
  visible: boolean
  record?: any
}
const props = withDefaults(defineProps<IProps>(), {
  visible: false
})
interface IEmits {
  (e: 'update:visible', value: boolean): void
  (e: 'refresh'): void
}
const emits = defineEmits<IEmits>()
const title = computed(() => (props?.record?.id ? '编辑规则' : '创建规则'))
const formRef = ref<FormInstance>()
const matchingView = ref()
const formData = ref({
  name: '',
  action: undefined,
  order: undefined,
  priority: undefined,
  scope: 3,
  module: 2,
  ttl: 1,
  cycle_unit: A_CACHE_TIME.SECOND,
  duration_unit: A_CACHE_TIME.SECOND,
  module_config: { count: 1000, cycle: 1, duration: 10 },
  response_page: {
    type: 1,
    code: 403,
    body: ''
  }
})
const formRules = computed<{ [key: string]: FieldRule[] }>(() => {
  return {
    name: [
      {
        required: true,
        message: '请输入规则名称'
      }
    ],
    action: [
      {
        required: true,
        message: '请选择执行动作'
      }
    ],
    ttl: [
      {
        required: true,
        message: '请输入'
      }
    ],
    order: [
      {
        required: true,
        message: '请选择执行优先级'
      }
    ],
    'module_config.count': [
      {
        required: true,
        message: '请输入'
      }
    ],
    'module_config.duration': [
      {
        required: true,
        message: '请输入持续时间'
      }
    ],
    'module_config.cycle': [
      {
        required: true,
        message: '请输入'
      }
    ],
    'response_page.body': [{ required: true, message: '请输入响应内容' }],
    'response_page.code': [
      { required: true, message: '请输入响应代码' },
      {
        validator: (value, callback) => {
          if (!/^4\d{2}$/.test(value)) {
            callback('输入 4XX 状态代码')
          } else {
            callback()
          }
        }
      }
    ],
    priority: [
      {
        required: true,
        message: '请选择自定义规则'
      }
    ]
  }
})
const ruleGroups = ref<IMatchingGroup[]>([
  {
    uuid: uuidV4(),
    rules: [
      {
        uuid: uuidV4(),
        field: '',
        operator: '',
        value: '',
        custom_field: ''
      }
    ]
  }
])

const setDefaultCode = (val: number) => {
  if (val === 1) formData.value.response_page.code = 403
}
const setDefaultType = (val: number) => {
  if (val === A_RESPONSE_TYPE.DEFAULT) {
    formData.value.response_page.code = 403
  } else {
    formData.value.response_page.code = undefined
  }
  formData.value.response_page.type = 1
}
const params = ref<CloudFilterBarState>({
  order: 'asc',
  sort: 'priority',
  scope: 3,
  module: 2
})
const list = ref<WafListItem[]>([])
const filterList = ref<WafListItem[]>([])
const { run, pagination } = useListRequest(getApiWafQueryApi, {
  params,
  immediate: false,
  afterFn(res) {
    list.value = res?.list || []
    if (!list.value.length) return
    filterList.value = res.list.filter((item) => item.id !== props?.record?.id)
  }
})
pagination.value.pageSize = 1000
const getOption = computed(() => {
  if (props.record?.id) {
    return list.value.length > 2 ? priorityOptions : priorityOptions.slice(0, 2)
  } else {
    return list.value.length > 1 ? priorityOptions : priorityOptions.slice(0, 2)
  }
})
const prePriority = ref(0)
const handleChange = (val) => {
  if (val === 2) {
    if (prePriority.value === list.value[0].priority) {
      formData.value.priority = prePriority.value + 1
    } else if (
      prePriority.value === list.value[list.value.length - 1].priority
    ) {
      formData.value.priority = prePriority.value - 1
    }
  }
}

const { request } = useRequest(getApiWafApi, {
  success(res: any) {
    Object.assign(formData.value, res)
    prePriority.value = res.priority!
    if (!res?.response_page) {
      formData.value.response_page = {
        type: A_RESPONSE_TYPE.DEFAULT,
        code: 403,
        body: ''
      }
    }
    const cycleData = separateNumberAndLetter(res?.module_config?.cycle)
    const durationData = separateNumberAndLetter(res?.module_config?.duration)
    formData.value.module_config.cycle = Number(cycleData.value)
    formData.value.module_config.duration = Number(durationData.value)
    formData.value.cycle_unit = cycleData.unit
    formData.value.duration_unit = durationData.unit
    ruleGroups.value[0].rules = res.conditions.map((item) => {
      return {
        uuid: uuidV4(),
        ...item,
        value:
          getFieldValue(item)!.count > 1 ? item.value : item.value.toString()
      }
    })
    if (list.value.length) {
      if (list.value.length === 1)
        return (formData.value.order = formData.value.priority)

      const priorityArr = list.value.map((item: WafListItem) => item.priority!)
      const min = Math.min(...priorityArr)
      const max = Math.max(...priorityArr)
      switch (+formData.value.priority!) {
        case min:
          formData.value.order = A_EXECUTION_PRIORITY.FIRST
          break
        case max:
          formData.value.order = A_EXECUTION_PRIORITY.LAST
          break
        default:
          formData.value.order = A_EXECUTION_PRIORITY.CUSTOM
      }
    } else {
      formData.value.order = formData.value.priority
    }
    if (formData.value.order === A_EXECUTION_PRIORITY.CUSTOM) {
      formData.value.priority = formData.value.priority + 1
    } else {
      formData.value.priority = formData.value.priority!
    }
  }
})
const handleBeforeOpen = async () => {
  await run()
  if (props.record) request({ id: props.record?.id })
}

const handleBeforeClose = async () => {
  formData.value.cycle_unit = A_CACHE_TIME.SECOND
  await formRef.value?.resetFields()
  matchingView.value?.reset()
  emits('update:visible', false)
  formData.value.cycle_unit = A_CACHE_TIME.SECOND
  formData.value.duration_unit = A_CACHE_TIME.SECOND
  formData.value.response_page = {
    type: 1,
    code: 403,
    body: ''
  }
}
const saveLoading = ref(false)
const handleSubmit = async () => {
  const error = await formRef.value?.validate()
  const error1 = await matchingView.value.validate()
  if (error || !error1) return false
  saveLoading.value = true
  const data: any = {
    ...omit(formData.value, 'priority', 'cycle_unit', 'duration_unit'),
    conditions: ruleGroups.value[0].rules.map((item) => {
      return {
        ...item,
        value: !Array.isArray(item.value)
          ? item.value
            ? [item.value]
            : []
          : item.value.filter(Boolean)
      }
    }),
    module_config: {
      ...formData.value?.module_config,
      cycle: formData.value?.module_config?.cycle + formData.value?.cycle_unit,
      duration:
        formData.value?.module_config?.duration + formData.value?.duration_unit
    },
    id: props.record ? props.record?.id : undefined
  }
  if (formData.value.action === A_EXECUTION_TYPE.OBSERVE)
    data.response_page = null
  if (formData.value?.order === A_EXECUTION_PRIORITY.FIRST) {
    data.priority = 1
  } else if (formData.value?.order === A_EXECUTION_PRIORITY.LAST) {
    data.priority = 0
  } else {
    data.priority = formData?.value?.priority
  }
  const api_path = props.record ? updateApiWafApi : addApiWafApi
  api_path(data)
    .then(() => {
      ToastUtils.success('操作成功')
      emits('update:visible', false)
      emits('refresh')
    })
    .finally(() => (saveLoading.value = false))
}
</script>

<style lang="less" scoped>
// :deep(.arco-form-item-label-col) {
//   @apply mb-0;
// }
</style>
